package com.linkallcloud.web.face.base;

import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.linkallcloud.core.annotation.LacLog;
import com.linkallcloud.core.domain.Domain;
import com.linkallcloud.core.dto.CheckResult;
import com.linkallcloud.core.dto.Trace;
import com.linkallcloud.core.exception.BizException;
import com.linkallcloud.core.exception.Exceptions;
import com.linkallcloud.core.face.message.request.FaceRequest;
import com.linkallcloud.core.face.message.request.IdFaceRequest;
import com.linkallcloud.core.face.message.request.ListFaceRequest;
import com.linkallcloud.core.face.message.request.ObjectFaceRequest;
import com.linkallcloud.core.face.message.request.PageFaceRequest;
import com.linkallcloud.core.face.message.request.ParentIdFaceRequest;
import com.linkallcloud.core.face.message.request.SidFaceRequest;
import com.linkallcloud.core.face.message.request.StatusFaceRequest;
import com.linkallcloud.core.face.message.request.StatussFaceRequest;
import com.linkallcloud.core.face.message.response.ErrorFaceResponse;
import com.linkallcloud.core.lang.Mirror;
import com.linkallcloud.core.lang.Strings;
import com.linkallcloud.core.manager.IManager;
import com.linkallcloud.core.pagination.Page;
import com.linkallcloud.core.query.Query;
import com.linkallcloud.core.query.WebQuery;
import com.linkallcloud.core.query.rule.Equal;
import com.linkallcloud.core.query.rule.desc.StringRuleDescriptor;
import com.linkallcloud.core.util.Domains;
import com.linkallcloud.core.www.ISessionBUser;
import com.linkallcloud.core.www.ISimpleUser;
import com.linkallcloud.web.face.annotation.Face;
import com.linkallcloud.web.utils.Controllers;

public abstract class BaseFace2<T extends Domain, S extends IManager<T>> extends CheckFace {

    protected Mirror<T> mirror;

    @SuppressWarnings("unchecked")
    public BaseFace2() {
        super();
        try {
            mirror = Mirror.me((Class<T>) Mirror.getTypeParams(getClass())[0]);
        } catch (Throwable e) {
            if (log.isWarnEnabled()) {
                log.warn("!!!Fail to get TypeParams for self!", e);
            }
        }
    }

    public Class<T> getDomainClass() {
        return (null == mirror) ? null : mirror.getType();
    }

    protected abstract S manager();

    @Face(simple = true)
    @RequestMapping(value = "/fetch", method = RequestMethod.POST)
    public @ResponseBody Object fetch(ParentIdFaceRequest faceReq, CheckResult cr, Trace t, HttpServletRequest request,
            ISimpleUser su) {
        // check(t, "fetch", faceReq, su);

        T entity = doFetch(t, faceReq, su, cr);
        if (entity != null) {
            entity.traceApp(t, su != null ? su.getApp() : null);
        }
        return convert(t, "fetch", faceReq, entity);
    }

    @Face(simple = true)
    @RequestMapping(value = "/find", method = RequestMethod.POST)
    public @ResponseBody Object find(ListFaceRequest faceReq, CheckResult cr, Trace t, HttpServletRequest request,
            ISimpleUser su) {
        // check(t, "find", faceReq, su);

        List<T> entities = doFind(t, faceReq.getQuery(), su, cr);
        return converts(t, "find", faceReq, entities);
    }

    protected List<T> doFind(Trace t, WebQuery wq, ISimpleUser su, CheckResult cr) {
        Query q = new Query();
        if (wq != null) {
            q = wq.toQuery();
        }
        return manager().find(t, q);
    }

    protected T doFetch(Trace t, ParentIdFaceRequest fr, ISimpleUser su, CheckResult cr) {
        if (fr.getId() == null || Strings.isBlank(fr.getUuid())) {
            // throw new BizException(Exceptions.CODE_ERROR_PARAMETER, "参数错误");
            return mirror.born();
        } else {
            return manager().fetchByIdUuid(t, fr.getId(), fr.getUuid());
        }
    }

    @LacLog(desc = "用户([(${su.sid.name})])保存了[(${domainShowName})]")
    @Face(simple = true)
    @RequestMapping(value = "/save", method = RequestMethod.POST)
    public @ResponseBody Object save(ObjectFaceRequest<T> fr, CheckResult cr, Trace t, HttpServletRequest request,
            ISimpleUser su) {
        // check(t, "save", fr, su);

        if (!Controllers.checkReferer(request, true)) {
            return new ErrorFaceResponse(Exceptions.CODE_ERROR_AUTH_PERMISSION, "Referer验证未通过");
        }
        T entity = fr.getData();
        doSave(t, entity, su, cr);
        return convert(t, "save", fr, entity);
    }

    protected void doSave(Trace t, T entity, ISimpleUser su, CheckResult cr) {
        if (entity.getId() != null && entity.getUuid() != null) {
            manager().update(t, entity);
        } else {
            if (Strings.isBlank(entity.getUuid())) {
                entity.setUuid(entity.generateUuid());
            }
            Long id = manager().insert(t, entity);
            entity.setId(id);
        }
    }

    @Face(simple = true)
    @RequestMapping(value = "/delete", method = RequestMethod.POST)
    @LacLog(desc = "用户([(${su.sid.name})])删除了[(${domainShowName})],ID([(${fr.id})])")
    public @ResponseBody Object delete(IdFaceRequest fr, CheckResult cr, Trace t, HttpServletRequest request,
            ISimpleUser su) {
        // check(t, "delete", fr, su);

        if (!Controllers.checkReferer(request, true)) {
            return new ErrorFaceResponse(Exceptions.CODE_ERROR_AUTH_PERMISSION, "Referer验证未通过");
        }
        if (fr.getId() == null || Strings.isBlank(fr.getUuid())) {
            throw new BizException(Exceptions.CODE_ERROR_DELETE, "参数错误");
        }
        return doDelete(t, fr.getId(), fr.getUuid(), su, cr);
    }

    protected Boolean doDelete(Trace t, Long id, String uuid, ISimpleUser su, CheckResult cr) {
        if (id == null || Strings.isBlank(uuid)) {
            throw new BizException(Exceptions.CODE_ERROR_PARAMETER, "参数错误");
        }
        return manager().delete(t, id, uuid);
    }

    @Face(simple = true)
    @RequestMapping(value = "/deletes", method = RequestMethod.POST)
    @LacLog(desc = "用户([(${su.sid.name})])删除了[(${domainShowName})],IDS([(${fr.uuidIds})])")
    public @ResponseBody Object deletes(SidFaceRequest fr, CheckResult cr, Trace t, HttpServletRequest request,
            ISimpleUser su) {
        // check(t, "deletes", fr, su);

        if (!Controllers.checkReferer(request, true)) {
            return new ErrorFaceResponse(Exceptions.CODE_ERROR_AUTH_PERMISSION, "Referer验证未通过");
        }
        if (fr.getUuidIds() == null || fr.getUuidIds().isEmpty()) {
            throw new BizException(Exceptions.CODE_ERROR_DELETE, "参数错误");
        }
        return doDeletes(t, fr.getUuidIds(), su, cr);
    }

    protected Boolean doDeletes(Trace t, Map<String, Long> uuidIds, ISimpleUser su, CheckResult cr) {
        if (uuidIds == null || uuidIds.isEmpty()) {
            throw new BizException(Exceptions.CODE_ERROR_PARAMETER, "参数错误");
        }
        return manager().deletes(t, uuidIds);
    }

    @LacLog(desc = "用户([(${su.sid.name})])修改了 [(${domainShowName})],ID([(${fr.id})])的状态为([(${fr.status})])")
    @Face(simple = true)
    @RequestMapping(value = "/changeStatus", method = RequestMethod.POST)
    public @ResponseBody Object changeStatus(StatusFaceRequest fr, CheckResult cr, Trace t, HttpServletRequest request,
            ISimpleUser su) {
        // check(t, "changeStatus", fr, su);

        if (!Controllers.checkReferer(request, true)) {
            return new ErrorFaceResponse(Exceptions.CODE_ERROR_AUTH_PERMISSION, "Referer验证未通过");
        }
        if (fr.getId() == null || Strings.isBlank(fr.getUuid())) {
            throw new BizException(Exceptions.CODE_ERROR_UPDATE, "参数错误");
        }
        return doChangeStatus(t, fr.getStatus(), fr.getId(), fr.getUuid(), su, cr);
    }

    protected Boolean doChangeStatus(Trace t, int status, Long id, String uuid, ISimpleUser su, CheckResult cr) {
        if (id == null || Strings.isBlank(uuid)) {
            throw new BizException(Exceptions.CODE_ERROR_PARAMETER, "参数错误");
        }
        return manager().updateStatus(t, status, id, uuid);
    }

    @LacLog(desc = "用户([(${su.sid.name})])修改了 [(${domainShowName})],IDS([(${fr.uuidIds})])的状态为([(${fr.status})])")
    @Face(simple = true)
    @RequestMapping(value = "/changeStatuss", method = RequestMethod.POST)
    public @ResponseBody Object changeStatuss(StatussFaceRequest fr, CheckResult cr, Trace t,
            HttpServletRequest request, ISimpleUser su) {
        // check(t, "changeStatuss", fr, su);

        if (!Controllers.checkReferer(request, true)) {
            return new ErrorFaceResponse(Exceptions.CODE_ERROR_AUTH_PERMISSION, "Referer验证未通过");
        }
        if (fr.getUuidIds() == null || fr.getUuidIds().isEmpty()) {
            throw new BizException(Exceptions.CODE_ERROR_UPDATE, "参数错误");
        }
        return doChangeStatuss(t, fr.getStatus(), fr.getUuidIds(), su, cr);
    }

    protected Boolean doChangeStatuss(Trace t, int status, Map<String, Long> uuidIds, ISimpleUser su, CheckResult cr) {
        if (uuidIds == null || uuidIds.isEmpty()) {
            throw new BizException(Exceptions.CODE_ERROR_PARAMETER, "参数错误");
        }
        return manager().updates(t, status, uuidIds);
    }

    @Face(simple = true)
    @RequestMapping(value = "/page", method = RequestMethod.POST)
    public @ResponseBody Object page(PageFaceRequest faceReq, CheckResult cr, Trace t, HttpServletRequest request,
            ISimpleUser su) {
        // check(t, "page", faceReq, su);

        Page<T> page = new Page<>(faceReq);
        page = doPage(t, page, su, cr);
        return convertPage(t, "page", faceReq, page);
    }

    protected Page<T> doPage(Trace t, Page<T> page, ISimpleUser su, CheckResult cr) {
        return manager().findPage(t, page);
    }

    @Face(simple = true)
    @RequestMapping(value = "/page4Select", method = RequestMethod.POST)
    public @ResponseBody Object page4Select(PageFaceRequest faceReq, CheckResult cr, Trace t,
            HttpServletRequest request, ISimpleUser su) {
        // check(t, "page4Select", faceReq, su);

        Page<T> page = new Page<>(faceReq);
        page = doPage4Select(t, page, su, cr);
        return convertPage(t, "page4Select", faceReq, page);
    }

    protected Page<T> doPage4Select(Trace t, Page<T> page, ISimpleUser su, CheckResult cr) {
        return manager().findPage4Select(t, page);
    }

    /**
     * 再次进行类型转换
     *
     * @param method
     * @param entity
     * @return
     */
    protected <X extends Domain> Object convert(Trace t, String method, FaceRequest fr, X entity) {
        return Domains.dataMasking(t, method, fr, entity);
    }

    protected <X extends Domain> Object converts(Trace t, String method, FaceRequest fr, List<X> entities) {
        return Domains.converts(t, method, fr, entities);
    }

    protected <X extends Domain> Object convertPage(Trace t, String method, FaceRequest fr, Page<X> page) {
        return Domains.convert(t, method, fr, page);
    }

    /**
     * fd：把登录用户的area信息作为查询条件加入page中
     *
     * @param page
     * @param suser
     */
    public void addAreaCnd2Page(Page<T> page, ISimpleUser suser) {
        filterArea(page, suser);
    }

    public void filterArea(Query query, ISimpleUser suser) {
        if (suser instanceof ISessionBUser) {
            ISessionBUser bsu = (ISessionBUser) suser;
            if (bsu.getArea() == null) {
                query.addRule(new Equal("level", 0));
                query.addRule(new Equal("areaId", 0L));
            } else {
                query.addRule(new Equal("level", bsu.getAreaLevel()));
                query.addRule(new Equal("areaId", bsu.areaId()));
            }
        }
    }

    /**
     * 
     * @param query
     * @param suser
     * @param suVisitAllCompanies
     *            超级管理员是否需要看全部单位的数据
     */
    public void filterCompanyQuery(Query query, ISimpleUser suser, boolean suVisitAllCompanies) {
        if (suser instanceof ISessionBUser) {
            ISessionBUser su = (ISessionBUser) suser;
            if (su.getLoginName().equals("superadmin")) {
                if (!suVisitAllCompanies) {
                    doFilterCompanyQuery(query, su.companyId(), su.getUserType());
                }
            } else {
                doFilterCompanyQuery(query, su.companyId(), su.getUserType());
            }
        }
    }

    public void doFilterCompanyQuery(Query query, Long companyId, String companyType) {
        if (query.hasRule4Field("companyId")) {
            Equal companyIdRule = (Equal) query.getRule4Field("companyId");
            companyIdRule.setValue(companyId);
        } else {
            query.addRule(new Equal("companyId", companyId));
        }
        if (query.hasRule4Field("companyType")) {
            Equal companyTypeRule = (Equal) query.getRule4Field("companyType");
            companyTypeRule.setValue(companyType);
        } else {
            query.addRule(new Equal("companyType", companyType));
        }
    }

    /**
     * 
     * @param query
     * @param suser
     * @param suVisitAllCompanies
     *            超级管理员是否需要看全部单位的数据
     */
    public void filterCompanyWebQuery(WebQuery query, ISimpleUser suser, boolean suVisitAllCompanies) {
        if (suser instanceof ISessionBUser) {
            ISessionBUser su = (ISessionBUser) suser;
            if (su.getLoginName().equals("superadmin")) {
                if (!suVisitAllCompanies) {
                    doFilterCompanyWebQuery(query, su.companyId(), su.getUserType());
                }
            } else {
                doFilterCompanyWebQuery(query, su.companyId(), su.getUserType());
            }
        }
    }

    public void doFilterCompanyWebQuery(WebQuery query, Long companyId, String companyType) {
        if (query.hasRule4Field("companyId")) {
            StringRuleDescriptor companyIdRule = query.getRule4Field("companyId");
            companyIdRule.setValue(companyId);
        } else {
            query.addRule(new StringRuleDescriptor("companyId", "eq", companyId, "L"));
        }
        if (query.hasRule4Field("companyType")) {
            StringRuleDescriptor companyTypeRule = query.getRule4Field("companyType");
            companyTypeRule.setValue(companyType);
        } else {
            query.addRule(new StringRuleDescriptor("companyType", "eq", companyType, "S"));
        }
    }

}
